/*
 * Copyright 2011 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.code.qsecurity.client.ui;

import java.util.List;

import com.google.code.qsecurity.shared.proxy.EmailVerificationProxy;
import com.google.code.qsecurity.shared.proxy.UserProxy;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.editor.client.Editor;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.TabLayoutPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.requestfactory.gwt.client.RequestFactoryEditorDriver;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.user.client.ui.Anchor;

/**
 * Sample implementation of {@link BaseView}.
 */
public class SecurityViewImpl extends PopupPanel implements QSecurityUI {

	interface Binder extends UiBinder<Widget, SecurityViewImpl> {
	}
	
	private static final Binder binder = GWT.create(Binder.class);
	
	private SecurityViewImpl viewInstance;
	private BaseViewImpl impl;

	@UiField LayoutPanel mainPanel;
	@UiField PushButton buttonClosePopup;
	@UiField TabLayoutPanel tabLayoutPanel;
	@UiField DivElement errorDiv;
	@UiField HTMLPanel errorPanel;
	
	// Login tab fields
	@UiField TextBox textBoxLoginEmail;
	@UiField PasswordTextBox pwTextBoxLoginPassword;
	@UiField PushButton buttonLogin;
	@UiField Anchor anchorForgottenPassword;
	
	// Signup tab fields
	@UiField TextBox textBoxName;
	@UiField TextBox textBoxSignupEmail;
	@UiField PasswordTextBox pwTextBoxSignupPassword;
	@UiField PasswordTextBox pwTextBoxRepeatPassword;
	@UiField PushButton buttonSignup;
	
	// Verification tab fields
	@UiField TextBox textBoxVerificationEmail;
	@UiField TextBox textBoxVerificationCode;
	@UiField PushButton buttonVerify;

	public SecurityViewImpl() {
		viewInstance = this;
		setWidget(binder.createAndBindUi(this));
	}
	
	private void setImpl(BaseViewImpl impl) {
		this.impl = impl;
	}

	@Override
	public LoginView getLoginView() {
		return new LoginViewImpl();
	}

	@Override
	public SignupView getSignupView() {
		return new SignupViewImpl();
	}

	@Override
	public VerificationView getVerificationView() {
		return new VerificationViewImpl();
	}

	@Override
	public ForgottenPasswordView getForgottenPasswordView() {
		return new ForgottenPasswordViewImpl();
	}
	
	abstract public class BaseViewImpl implements BaseView {

		abstract protected SecurityPresenter getPresenter();

		@Override
		public Widget asWidget() {
			return viewInstance.asWidget();
		}

		@Override
		public void displayErrors(List<String> errors) {
			final int LINE_HEIGHT = 16;  // px
			SafeHtmlBuilder b = new SafeHtmlBuilder();
			for (String err : errors) {
	            b.appendEscaped(err).appendHtmlConstant("<br>");
			}
			errorDiv.setInnerHTML(b.toSafeHtml().asString());
			mainPanel.setWidgetBottomHeight(errorPanel, 0, Unit.PX, LINE_HEIGHT*errors.size(), Unit.PX);
			mainPanel.animate(1000);
		}

		@Override
		public void refresh() {
			mainPanel.setWidgetBottomHeight(errorPanel, 0, Unit.PX, 0, Unit.PX);
			mainPanel.animate(500);
			errorDiv.setInnerHTML("");
		}
		
		public void handleKeyPress(KeyPressEvent event) {
			if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
				submit();
			}
		}

		abstract public void submit();

		@Override
		public void exit() {
			viewInstance.hide();
			refresh();
		}

		void viewSwitched(int index) {
			getPresenter().viewSwitched(index);
		}
		
		public void viewClosedByUser() {
			exit();
			getPresenter().viewClosed();
		}
		
	}

	interface LoginDriver extends RequestFactoryEditorDriver<UserProxy, LoginViewImpl> {
	}
	
	public class LoginViewImpl extends BaseViewImpl implements LoginView, Editor<UserProxy> {
		
		private LoginPresenter presenter;
		
		public LoginViewImpl() {
			buttonLogin.addClickHandler(new ClickHandler() {

				@Override
				public void onClick(ClickEvent event) {
					presenter.login();
				}
				
			});
			
			anchorForgottenPassword.addClickHandler(new ClickHandler() {

				@Override
				public void onClick(ClickEvent event) {
					presenter.forgottenPasswordClicked();
				}
				
			});
		}

		@Override
		public void init(LoginPresenter presenter) {
			this.presenter = presenter;
			viewInstance.setImpl(this);
			tabLayoutPanel.selectTab(LOGIN_TAB_INDEX, false);
			viewInstance.center();
		}

		@Override
		protected SecurityPresenter getPresenter() {
			return presenter;
		}

		@Override
		public RequestFactoryEditorDriver<UserProxy, Editor<UserProxy>> createEditorDriver() {
			RequestFactoryEditorDriver<UserProxy, Editor<UserProxy>> driver = GWT.create(LoginDriver.class);
			driver.initialize(this);
			return driver;
		}

		@Override
		public void submit() {
			presenter.login();
		}
		
		@Path("email")
		TextBox getUserEmailTextBox() {
			return viewInstance.textBoxLoginEmail;
		}
		
		@Path("hashedPassword")
		PasswordTextBox getUserPasswordTextBox() {
			return viewInstance.pwTextBoxLoginPassword;
		}
		
	}
	
	interface SignupDriver extends RequestFactoryEditorDriver<UserProxy, SignupViewImpl> {
	}
	
	public class SignupViewImpl extends BaseViewImpl implements SignupView, Editor<UserProxy> {
		
		private SignupPresenter presenter;
		
		public SignupViewImpl() {
			buttonSignup.addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					presenter.signup(pwTextBoxRepeatPassword.getText());
				}
			});
			
			pwTextBoxRepeatPassword.addChangeHandler(new ChangeHandler() {
				@Override
				public void onChange(ChangeEvent event) {
					presenter.passwordsEntered(pwTextBoxSignupPassword.getText(),
							pwTextBoxRepeatPassword.getText());
				}
			});
		}

		@Override
		protected SecurityPresenter getPresenter() {
			return presenter;
		}

		@Override
		public RequestFactoryEditorDriver<UserProxy, Editor<UserProxy>> createEditorDriver() {
			RequestFactoryEditorDriver<UserProxy, Editor<UserProxy>> driver = GWT.create(SignupDriver.class);
			driver.initialize(this);
			return driver;
		}

		@Override
		public void init(SignupPresenter presenter) {
			this.presenter = presenter;
			viewInstance.setImpl(this);
			tabLayoutPanel.selectTab(SIGNUP_TAB_INDEX, false);
			viewInstance.center();
		}

		@Override
		public void submit() {
			presenter.signup(pwTextBoxRepeatPassword.getText());
		}
		
		@Path("name")
		TextBox getUserNameTextBox() {
			return viewInstance.textBoxName;
		}
		
		@Path("email")
		TextBox getUserEmailTextBox() {
			return viewInstance.textBoxSignupEmail;
		}
		
		@Path("hashedPassword")
		PasswordTextBox getUserPasswordTextBox() {
			return viewInstance.pwTextBoxSignupPassword;
		}
		
	}
	
	interface VerificationDriver extends RequestFactoryEditorDriver<EmailVerificationProxy, VerificationViewImpl> {
	}
	
	public class VerificationViewImpl extends BaseViewImpl implements VerificationView, Editor<EmailVerificationProxy> {
		
		private VerificationPresenter presenter;
		
		public VerificationViewImpl() {
			buttonVerify.addClickHandler(new ClickHandler() {

				@Override
				public void onClick(ClickEvent event) {
					presenter.verify();
				}
				
			});
		}

		@Override
		protected SecurityPresenter getPresenter() {
			return presenter;
		}

		@Override
		public RequestFactoryEditorDriver<EmailVerificationProxy, Editor<EmailVerificationProxy>> createEditorDriver() {
			RequestFactoryEditorDriver<EmailVerificationProxy, Editor<EmailVerificationProxy>> driver =
					GWT.create(VerificationDriver.class);
			driver.initialize(this);
			return driver;
		}

		@Override
		public void init(VerificationPresenter presenter) {
			this.presenter = presenter;
			viewInstance.setImpl(this);
			tabLayoutPanel.selectTab(VERIFICATION_TAB_INDEX, false);
			viewInstance.center();
		}

		@Override
		public void setEmail(String email) {
			textBoxVerificationEmail.setText(email);
		}

		@Override
		public void submit() {
			presenter.verify();
		}
		
		@Path("email")
		TextBox getUserEmailTextBox() {
			return viewInstance.textBoxVerificationEmail;
		}
		
		@Path("code")
		TextBox getVerificationCodeTextBox() {
			return viewInstance.textBoxVerificationCode;
		}
		
	}
	
	public class ForgottenPasswordViewImpl extends BaseViewImpl implements ForgottenPasswordView {
		
		private ForgottenPasswordPresenter presenter;
		
		public ForgottenPasswordViewImpl() {
			buttonVerify.addClickHandler(new ClickHandler() {

				@Override
				public void onClick(ClickEvent event) {
					presenter.sendButtonClicked();
				}
				
			});
			
			buttonVerify.addClickHandler(new ClickHandler() {

				@Override
				public void onClick(ClickEvent event) {
					presenter.sendButtonClicked();
				}
				
			});
		}

		@Override
		public void init(ForgottenPasswordPresenter presenter) {
			// TODO Auto-generated method stub
			
		}

		@Override
		protected SecurityPresenter getPresenter() {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public void submit() {
			// TODO Auto-generated method stub
			
		}
		
	}

	@UiHandler("buttonClosePopup")
	void onButtonClosePopupClick(ClickEvent event) {
		impl.viewClosedByUser();
	}

	@UiHandler("tabLayoutPanel")
	void onTabLayoutPanelSelection(SelectionEvent<Integer> event) {
		impl.viewSwitched(event.getSelectedItem().intValue());
	}
	
	@UiHandler("textBoxLoginEmail")
	void onTextBoxLoginEmailKeyPress(KeyPressEvent event) {
		impl.handleKeyPress(event);
	}
	
	@UiHandler("pwTextBoxLoginPassword")
	void onPwTextBoxLoginPasswordKeyPress(KeyPressEvent event) {
		impl.handleKeyPress(event);
	}
	
	@UiHandler("textBoxName")
	void onTextBoxNameKeyPress(KeyPressEvent event) {
		impl.handleKeyPress(event);
	}
	
	@UiHandler("textBoxSignupEmail")
	void onTextBoxSignupEmailKeyPress(KeyPressEvent event) {
		impl.handleKeyPress(event);
	}
	
	@UiHandler("pwTextBoxSignupPassword")
	void onPwTextBoxSignupPasswordKeyPress(KeyPressEvent event) {
		impl.handleKeyPress(event);
	}
	
	@UiHandler("pwTextBoxRepeatPassword")
	void onPwTextBoxRepeatPasswordKeyPress(KeyPressEvent event) {
		impl.handleKeyPress(event);
	}
	
	@UiHandler("textBoxVerificationEmail")
	void onTextBoxVerificationEmailKeyPress(KeyPressEvent event) {
		impl.handleKeyPress(event);
	}
	
	@UiHandler("textBoxVerificationCode")
	void onTextBoxVerificationCodeKeyPress(KeyPressEvent event) {
		impl.handleKeyPress(event);
	}
}
